home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
libs
/
knowhow4
/
fill.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-10
|
9KB
|
320 lines
/* Fill functions, (C) as the part of KNOW-HOW.DRAW, HOTKEY DRAW,
HOTKEY PLOT and HOTKEY OBJECT DRAW packages.
This file contains floodfill function for BGI
library. The area may be represented as two-dimentional vessel, which
we fill with water, in the absence of athmosphere.
*/
#include <stdlib.h>
#include <conio.h>
#include <mem.h>
#include "pixel.h"
#include "graphpp.h"
enum { DN, LEFT, RIGHT, L_DN, R_DN, UP, L_UP, R_UP, NO };
rect level[640]; // there are <= 640 elements in this realization,
// the VGA horiz. dimention. Using left-to-right filling
// we may use 480 elements
char flag; // draw_line (1) or go_local (0)
int used; // number of elements in level[]
int local; // is it local min ?
rect work; // used to avoid copying
rect bound; // outline of the area to fill, used to avoid copying
int start_color; // color in the start pixel, used to avoid copying
int attr, bak; // colors, used to avoid additional copying in put_pixel()
// calls
char* fill; // fill pattern
/////////////////////////////
inline int get_pixel(loc p) // is this pixel
{ // have color ==
if(getpixel(p) != start_color || !bound.contains(p)) // start_color,
return 0; // and is it inside
return 1; // of bound (work
} // area
inline int get_pixel(int x, int y) { return get_pixel(loc(x, y)); }
////////////////////////////
inline void putPixel(loc pos)
{
if(!global_i[8])
put_pixel(pos.X, pos.Y, global_i[9]);
else
put_pixel_error_prop(pos.X, pos.Y, global_i[9], 48);
}
////////////////////////////
int inside(loc p) // is there any line under current pixel ?
{
for(int i = 0; i < used; i++)
{
if(p.Y > level[i].origin.Y - 1)
continue;
else if(p.Y < level[i].origin.Y - 1)
return 0;
if(p.X <= level[i].corner.X && p.X >= level[i].origin.X)
return 1;
}
return 0;
}
///////////////////////
int go_local(int left = 1) // go to the local minimum under the current
{ // pixel. "left" is used to block left moving
int i = 1; // if we use the same start and fill colors
loc pos = getCP(); // and can not begin from step down
while(1)
{
if(get_pixel(pos.X, pos.Y + 1) && !inside(pos))
{ moveto(pos = loc(pos.X, pos.Y + 1)); i = 0; } // left = 1; }
else if(left && get_pixel(pos.X - 1, pos.Y))
{ moveto(pos = loc(pos.X - 1, pos.Y)); i = 0; }
else break;
}
local = 1;
return i;
}
////////////////////////
rect get_line() // return the line under current
{ // pixel
loc pos = getCP();
rect line_below = rect(pos, pos);
for(int i = 0; i <= used; i++)
{
if(level[i].corner.Y == pos.Y && level[i].contains(pos))
{
line_below = level[i];
break;
}
}
return line_below;
}
///////////////////////
void remove(rect r) // remove line from array
{
for(int i = 0; i <= used; i++)
{
if(level[i].origin.Y == r.origin.Y
&& level[i].origin.X == r.origin.X)
{
for(; i <= used; i++)
level[i] = level[i + 1];
used--;
break;
}
}
}
///////////////////////
void add(rect r) // add line to array. Lines are sorted
{ // by Y, then by X
int i;
for(i = 0; i <= used; i++)
{
if(level[i].origin.Y == r.origin.Y && level[i].origin.X > r.origin.X)
break;
else if(level[i].origin.Y > r.origin.Y)
break;
}
for(int j = used; j >= i; j--)
level[j + 1] = level[j];
if(i > used)
i--;
level[i] = r;
work = r;
used++;
}
///////////////////////////
void draw_line() // draws line with current colors and pattern
{
flag = 1;
loc pos = getCP();
rect line_below = get_line(); // if we draw line above any other
rect new_rect; // contains new line
remove(line_below);
loc p = getCP();
if(!local) // it is not local minimum
{
moveto(loc(line_below.origin.X, line_below.origin.Y - 1)); // go up
while(1)
{
p = getCP();
if((!get_pixel(p)) // no place above leftmost pixel
&& line_below.corner.X >= p.X) // and we can move right
{
if(line_below.corner.X == p.X) // if it is the end of
{ // line_below
if(!used) // if no ways from this
flag = 0; // point
break;
}
else moveto(loc(p.X + 1, p.Y));
}
else break;
}
while(1)
{
p = getCP();
if((get_pixel(p.X - 1, p.Y)) // left, but not dn
&& get_pixel(p)
&& (!get_pixel(p.X, p.Y + 1)
|| p.X >= line_below.origin.X) // or we are above
&& !inside(loc(p.X - 1, p.Y - 1))) // and no intersection
moveto(p.X - 1, p.Y); // with other lines
else
{
if(line_below.origin.X > p.X // we can go_local
&& get_pixel(p.X, p.Y + 1))
flag = 0;
break;
}
}
}
int mark = 0;
if(get_pixel(p)) // first pixel of line
{
putPixel(p);
mark = 1; // mark that at least one pixel drawn
}
new_rect = rect(p, p);
int disable = 1; // first time impossible to put pixel
while(1)
{
p = loc(p.X + 1, p.Y);
if( mark
&& get_pixel(p)
&& (p.X <= line_below.corner.X
|| (!get_pixel(p.X, p.Y + 1)
|| inside(p))))
{
putPixel(p); // draw line in cycle
if(disable)
new_rect.corner = p;
else
new_rect.origin = p;
disable = 1;
}
else
{
if(disable && mark) // all with this line
add(new_rect);
if(get_pixel(p.X, p.Y + 1) // we can go_local
&& get_pixel(p))
flag = 0;
if(p.X >= line_below.corner.X)
break;
else
new_rect = rect(p, loc(line_below.corner.X,
line_below.corner.Y - 1));
disable = 0;
}
moveto(p);
}
local = 0;
}
////////////////////////
void dump_levels() // simplify the level[]
{
for(int i = 0; i < used; i++)
for(int j = i + 1; j < used; j++)
{
if(level[i].origin.X - 1 == level[j].corner.X
&& level[i].origin.Y == level[j].origin.Y)
{
level[i].origin.X = level[j].origin.X;
remove(level[j]);
}
if(level[i].corner.X + 1 == level[j].origin.X
&& level[i].origin.Y == level[j].origin.Y)
{
level[i].corner.X = level[j].corner.X;
remove(level[j]);
}
if(level[i].corner.X >= level[j].origin.X
&& level[i].origin.X <= level[j].corner.X
&& level[i].origin.Y == level[j].origin.Y - 1)
{
if(level[i].origin.X <= level[j].origin.X)
level[j].origin.X = level[i].corner.X;
else
level[j].corner.X = level[i].origin.X;
if(level[j].origin.X >= level[j].corner.X)
remove(level[j]);
}
}
}
////////////////////////
void fill_cell() // fill before it is possible to go_local
{
while(flag && used && !kbhit())
{
loc pos = getCP();
if(pos.Y == 75)
pos.Y = 75;
moveto(level[used - 1].corner);
draw_line();
dump_levels();
}
if(kbhit())
for(int i = 0; i < 640; i++)
level[i] = rect(0, 0, 0, 0);
}
////////////////////////
void fill_area(loc from, int a, int b, char* f,
rect r = rect(0, 0, getmaxx(), getmaxy()))
{
memset(level, 0, 640 * sizeof(rect));
if(!r.contains(from))
return;
flag = 1;
moveto(from);
start_color = getpixel(from);
attr = a; bak = b; bound = r; fill = f;
go_local(); // go to start position
draw_line(); // draw the first line and add first line to level[]
while(1)
{
if(flag)
fill_cell();
flag = 1;
if(!used)
return;
moveto(work.origin);
if(go_local()) // left local min
{
moveto(work.corner.X + 1, work.corner.Y);
if(go_local(0)) // right local min
return;
}
draw_line();
}
}
////////////////////////
/*
void main()
{
int gdriver = DETECT, gmode;
initgraph(&gdriver, &gmode, "..\\BGI");
flag = 0;
used = 0;
circle(120, 120, 100);
line(80, 80, 100, 100);
line(100, 100, 120, 100);
line(120, 100, 140, 75);
loc from(125, 125);
// char fill[] = { 255, 255, 255, 255, 255, 255, 255, 254 };
char fill_pattern[] = { 255, 55, 25, 5, 1, 215, 155, 15 };
int attr = GREEN;
int bak = BLACK;
fill_area(from, attr, bak, fill_pattern); //, r);
}
*/